<template>
  <div class="search-box">
    <div class="flex">
      <div>
        <el-icon><Search /></el-icon><span>筛选搜索</span>
      </div>
      <div>
        <el-button @click="resetForm">重置</el-button>
        <el-button @click="submitFn" type="primary">查询搜索</el-button>
      </div>
    </div>
    <div style="padding-top: 20px">
      <!-- 在input里面回车会造成刷新，大家今晚可以尝试解决一下 -->
      <el-form
        @submit.prevent="submitFn"
        ref="searchFormRef"
        :model="listParams"
      >
        <el-form-item prop="keyword" label="账号/姓名:" label-width="120px">
          <el-input v-model="listParams.keyword"></el-input>
        </el-form-item>
      </el-form>
    </div>
  </div>

  <div class="add-box">
    <el-button type="primary" @click="addUser">添加</el-button>
  </div>

  <el-table :data="tableData" style="width: 100%">
    <el-table-column prop="id" label="编号"> </el-table-column>
    <el-table-column prop="username" label="账号"></el-table-column>
    <el-table-column prop="nickName" label="姓名"></el-table-column>
    <el-table-column prop="email" label="邮箱"></el-table-column>
    <el-table-column prop="createTime" label="创建时间">
      <template #default="scope">
        {{ fomatDate(scope.row.createTime) }}
      </template>
    </el-table-column>
    <el-table-column prop="loginTime" label="登录时间">
      <template #default="scope">
        {{ fomatDate(scope.row.loginTime) }}
      </template>
    </el-table-column>
    <el-table-column label="是否启用">
      <!-- 通过插件得到的scope.row是每一列里面的 数据对象 -->
      <template #default="scope">
        <el-switch
          v-model="scope.row.status"
          :active-value="1"
          :inactive-value="0"
          @change="changeHandle(scope.row)"
        />
      </template>
    </el-table-column>
    <el-table-column label="操作">
      <template #default="scope">
        <el-button link type="primary" @click="handleEdit(scope.row.id)"
          >分配角色</el-button
        >
        <el-button link type="primary" @click="editHandle(scope.row.id)"
          >编辑</el-button
        >
      </template>
    </el-table-column>
  </el-table>
  <!-- 如果只有某个组件需要汉化，这么包着就行 -->
  <ElConfigProvider :locale="zhCn">
    <el-pagination
      v-model:currentPage="listParams.pageNum"
      v-model:page-size="listParams.pageSize"
      background
      layout="total, sizes, prev, pager, next ,jumper"
      :total="total"
      @size-change="pageSizeChagne"
      @current-change="currentChagne"
      :page-sizes="[10, 20, 50, 100]"
    />
  </ElConfigProvider>

  <EditUserVue
    :show="showEditUser"
    @hide="hideDialog"
    @refresh="getList"
    :data="editId"
  />

  <AllocRoleVue
    :show="showAllocRole"
    @hide="hideAllocRole"
    :data="allocRoleId"
  />
</template>

<script lang="ts" setup>
import EditUserVue from "./components/EditUser.vue";
import { ElConfigProvider, FormInstance } from "element-plus";
// element里面就已经帮我们准备好的 不同语言包，直接使用就行
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import { user } from "@/api";
import { reactive, ref, toRefs } from "vue";
import { fomatDate } from "@/utils";
import { ElMessage } from "element-plus";
import { Search } from "@element-plus/icons-vue";
import AllocRoleVue from "./components/AllocRole.vue";

interface IState {
  tableData: IUserModel[];
  listParams: IUserListParams;
  total: number;
}
// 一般如果遇上有部分数据是复杂类型，希望它们是响应式的，一般先准备一个总的state
const state = reactive<IState>({
  tableData: [],
  listParams: {
    keyword: "",
    pageNum: 1,
    pageSize: 10,
  },
  total: 0,
});

const searchFormRef = ref<FormInstance>();

const getList = () => {
  // 搜索跟之前第一次请求的不同就是 搜索要带 输入框里面的数据
  user.getUserListApi(state.listParams).then((res) => {
    if (res.code === 200) {
      state.tableData = res.data.list;
      state.total = res.data.total;
    }
  });
};
// 一开始的时候需要先调用一次
getList();

const submitFn = () => {
  // 搜索一定要把 页码调整为第一页
  state.listParams.pageNum = 1;
  // 重新请求一个数组回来把数据渲染到表格里面
  getList();
};

const pageSizeChagne = (val: number) => {
  // 如果当前已经是最一页，我们之前希望有提示，但是基于我们之前数据没有更多了，数据也不会更新才有这样的一个需求
  // 但是现在我们完成后续的工作之后，已经没有这个问题了
  // 目前存在的问题是： 修改了 pageSize 之后，发两次请求，目前没有太好的办法解决，先放着
  getList();
};

const currentChagne = (val: number) => {
  // val是新的页码
  // console.log(val);
  //   获取新的数据进行渲染
  getList();
};

// 分配角色的组件是否显示
const showAllocRole = ref(false);
// 分配角色的id
const allocRoleId = ref(0);
const handleEdit = (id: number) => {
  showAllocRole.value = true;
  allocRoleId.value = id;
};

const hideAllocRole = () => {
  showAllocRole.value = false;
  allocRoleId.value = 0;
};

// 这个是当前点击的编辑的id
const editId = ref(0);

// 编辑功能的一般流程：
// 1.从服务器获取旧的数据展示在页面中
// 2.在表单里面修改完毕
// 3.把最新的数据 向服务器发请求 同步到服务器
const editHandle = (id: number) => {
  // 向服务器获取数据，是在这里获取了再传入 子组件(EditUser)
  // 还是 把id 传递给 子组件，让它自己内部实现请求 ---> 用这种
  // 这部分获取数据并渲染的代码，是完全可以被我们封闭在组件内，不会有任何的改变
  // 就需要把一个id传入 子组件(EditUser)
  editId.value = id;
  // 把编辑框显示出来
  showEditUser.value = true;
};

const changeHandle = (row: IUserModel) => {
  user
    .updateUserStatusApi({
      id: row.id,
      status: row.status,
    })
    .then((res) => {
      ElMessage({
        message: res.message,
        type: res.code === 200 ? "success" : "error",
      });
      //  如果这个地方， res.code 不是200 其实也要把 switch 恢复
    })
    .catch((err) => {
      // 如果请求失败，会走catch
      // 把 switch 恢复成之前的状态 -
      // 方式1
      row.status = row.status === 1 ? 0 : 1;
      // 方式2
      //   let target = state.tableData.find((item) => item.id === row.id);
      //   target && (target.status = row.status === 1 ? 0 : 1);
    });
};

// 重置功能的实现：
// 1. 点击事件
// 2. 需要给el-from表单组件添加一个ref属性，得到该组件的实例
// 3. 点击的时候调用 组件实例的resetFields方法进行重置
// 4. 前提是 给 el-from 设置了 model 属性
// 5. 还需要给 el-form-item 设置相应的 prop 属性
const resetForm = () => {
  searchFormRef.value?.resetFields();
};

// 控制 EidtUser 组件是否显示的 变量
const showEditUser = ref(false);

const addUser = () => {
  // 控制 EditUser 显示
  showEditUser.value = true;
};

const hideDialog = () => {
  showEditUser.value = false;
  // 还要把 editId 归 0
  editId.value = 0;
};

// state是一个响应式数据，但是我们如果在 tempatle里面使用 state里面的数据，需要 使用 state 点出来
// 一般会使用 toRefs 把里面的数据解构成多个响应式子数据
let { tableData, listParams, total } = toRefs(state);
</script>

<style lang="less" scoped>
.search-box {
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 10px;
  .flex {
    display: flex;
    justify-content: space-between;
  }
}
.add-box {
  display: flex;
  justify-content: flex-end;
  padding: 10px;
  margin: 20px;
  border-radius: 10px;
  box-shadow: 0 0 4px 2px #ccc;
}
</style>
